package com.podium.web.system.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.podium.auth.entity.LoginUser;
import com.podium.auth.service.TokenService;
import com.podium.comment.exceptional.BaseException;
import com.podium.comment.utils.RequestUtils;
import com.podium.comment.utils.SequentialIdGenerator;
import com.podium.comment.utils.cache.CacheUtils;
import com.podium.web.log.entity.SysLoginLog;
import com.podium.web.log.service.SysLoginLogService;
import com.podium.web.system.controller.dto.LoginDto;
import com.podium.web.system.entity.SysUser;
import com.podium.web.system.service.LoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Date;
import java.util.Random;
import java.util.UUID;

/**
 * @author 邵文泽
 * @description 登录业务实现类
 * @date 2025/4/15 16:50
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private SysLoginLogService loginLogService;
    @Autowired
    private SequentialIdGenerator idGenerator;
    @Autowired
    private CacheUtils cacheUtils;

    @Override
    public String login(LoginDto loginDto) {
        SysLoginLog loginLog = initLoginLog(loginDto);
        try {
            if (loginDto.getCode() == null || loginDto.getCode().isEmpty()) {
                throw new BaseException("验证码不能为空！");
            }
            if (loginDto.getUuid() == null || loginDto.getUuid().isEmpty()) {
                throw new BaseException("验证码不能为空！");
            }
            String verifyCode = cacheUtils.getCacheObject(loginDto.getUuid(), String.class);
            if (verifyCode == null || !verifyCode.equals(loginDto.getCode())) {
                cacheUtils.removeCache(loginDto.getUuid());
                loginLog.setFailureReason("验证码错误！");
                loginLog.setLoginStatus(1L);

                throw new BaseException("验证码错误！");
            }
            Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword()));
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            String jwtToken = tokenService.createToken(loginUser);

            cacheUtils.removeCache(loginDto.getUuid());

            loginUser.setUserId(loginUser.getUserId());
            if (loginUser.getUser() instanceof SysUser sysUser) {
                loginLog.setNickName(sysUser.getNickName());
            }
            loginLog.setUserId(loginUser.getUserId());
            loginLog.setToken(loginUser.getToken());
            loginLog.setLoginStatus(0L);

            return jwtToken;
        } catch (AuthenticationException e) {
            if (e instanceof BadCredentialsException) {
                loginLog.setFailureReason("账号或密码错误！");
                loginLog.setLoginStatus(1L);
                cacheUtils.removeCache(loginDto.getUuid());
                throw new BaseException("账号或密码错误！");
            }
            throw new RuntimeException(e);
        } finally {
            loginLogService.asyncSaveLog(loginLog);
        }
    }

    /**
     * 初始化登录日志
     *
     * @param loginDto 登录请求参数
     * @return loginLog
     */
    private SysLoginLog initLoginLog(LoginDto loginDto) {
        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setId(String.valueOf(idGenerator.nextId()));
        loginLog.setUsername(loginDto.getUsername());
        loginLog.setLoginTime(new Date());
        loginLog.setLoginIp(RequestUtils.getIpAddress());
        loginLog.setDeviceInfo(RequestUtils.getDeviceInfo());
        loginLog.setRequestParam(JSONObject.toJSONString(loginDto));
        loginLog.setUserAgent(RequestUtils.getUserAgent());
        return loginLog;
    }

    @Override
    public JSONObject verifyCode() {
        try {
            int width = 120;
            int height = 38;
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = image.getGraphics();
            Random random = new Random();

            // 设置背景色
            g.setColor(new Color(220, 223, 230));
            g.fillRect(0, 0, width, height);

            // 设置字体
            Font font = new Font(Font.MONOSPACED, Font.BOLD, 18);
            g.setFont(font);

            String[] operators = new String[]{"+", "-", "*", "/"};
            String operator = operators[random.nextInt(operators.length)];
            String verifyCode = "", captcha = "";
            int a, b;
            switch (operator) {
                case "+":
                    a = random.nextInt(1, 9);
                    b = random.nextInt(1, 9);
                    verifyCode = String.valueOf(a + b);
                    captcha = a + " + " + b + " = ?";
                    break;
                case "*":
                    a = random.nextInt(1, 9);
                    b = random.nextInt(1, 9);
                    verifyCode = String.valueOf(a * b);
                    captcha = a + " * " + b + " = ?";
                    break;
                case "-":
                    a = random.nextInt(1, 8);
                    b = random.nextInt(1, 9);
                    a = a + b;
                    verifyCode = String.valueOf(a - b);
                    captcha = a + " - " + b + " = ?";
                    break;
                case "/":
                    a = random.nextInt(1, 9);
                    b = random.nextInt(1, 9);
                    a = a * b;
                    System.out.println("a = " + a);
                    System.out.println("b = " + b);
                    verifyCode = String.valueOf(a / b);
                    captcha = a + " ÷ " + b + " = ?";
                    break;
                default:
                    break;

            }

            g.setColor(new Color(48, 49, 51));
            g.drawString(captcha, 10, 27);

            // 将图片转换为base64格式
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(image, "png", byteArrayOutputStream);
            byte[] imageBytes = byteArrayOutputStream.toByteArray();
            String base64Image = Base64.getEncoder().encodeToString(imageBytes);

            UUID uuid = UUID.randomUUID();
            cacheUtils.setCacheObject(uuid.toString(), verifyCode, 5);

            JSONObject result = new JSONObject();
            result.put("verifyCode", base64Image);
            result.put("uuid", uuid.toString());
            return result;
        } catch (IOException e) {
            log.error("生成验证码失败", e);
            throw new BaseException("验证码获取失败，请稍后重试！");
        }
    }

}
